#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <memory>
#include "InetAddr.hpp"
#include "Log.hpp"

// 模版方法模式
namespace socket_ns
{
    class Socket;
    const static int gbacklog = 8;
    using socket_sptr = std::shared_ptr<Socket>;

    enum
    {
        SOCKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
        USAGE_ERROR
    };

    class Socket
    {
    public:
        virtual void CreateSocketOrDie() = 0;
        virtual void BindSocketOrDie(InetAddr &addr) = 0;
        virtual void ListenSocketOrDie() = 0;
        virtual socket_sptr Accepter(InetAddr *addr) = 0;
        virtual bool Connetcor(InetAddr &addr) = 0;
        virtual void SetSocketAddrReuse() = 0;
        virtual int SockFd() = 0;
        virtual int Recv(std::string *out) = 0;
        virtual int Send(const std::string &in) = 0;
        virtual void Close() = 0;


    public:
        void BuildListenSocket(InetAddr &addr)
        {
            CreateSocketOrDie();
            SetSocketAddrReuse();
            BindSocketOrDie(addr);
            ListenSocketOrDie();
        }
        bool BuildClientSocket(InetAddr &addr)
        {
            CreateSocketOrDie();
            return Connetcor(addr);
        }
    };




    class TcpSocket : public Socket//继承socket
    {
    public:
        TcpSocket(int fd = -1) : _sockfd(fd)
        {
        }
        void CreateSocketOrDie() override
        {
            // 1. 创建流式套接字
           _sockfd=socket(AF_INET,SOCK_STREAM,0);
           if(_sockfd<0)
           {
                LOG(FATAL,"创建socket失败");
                return;
           }
           return;

           
        }
        
        void BindSocketOrDie(InetAddr &addr) override
        {
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family=AF_INET;
            local.sin_port=addr.GetPort();
            local.sin_addr.s_addr=INADDR_ANY;
            int n=bind(_sockfd,(const sockaddr*)&local,sizeof(local));
            return ;

        
        }
        void ListenSocketOrDie() override
        {
           int n=listen(_sockfd,gbacklog);
           if(n<0)
           {
            LOG(ERROR,"监听失败");
           }
           else
           {
            LOG(DEBUG,"监听成功");
           }
           return;
        }
        socket_sptr Accepter(InetAddr *addr) override
        {
           
           struct sockaddr_in peer;
           socklen_t len=sizeof(peer);
           int sockfd=accept(_sockfd,(struct sockaddr*)&peer,&len);
           if(sockfd<0)
           {
            LOG(ERROR,"accept失败");
            return nullptr;
           }

            socket_sptr sock = std::make_shared<TcpSocket>(sockfd);
            return sock;
            
        }
        virtual bool Connetcor(InetAddr &addr)
        {
            // tcp client 要bind，不要显示的bind.
           struct sockaddr_in server;
            memset(&server, 0, sizeof(server));
           server.sin_family=AF_INET;
           server.sin_addr.s_addr=inet_addr(addr.GetIp().c_str());
           int n=connect(_sockfd,(struct sockaddr*)&server,sizeof(server));
           if(n<0)
           {
            LOG(ERROR,"connect失败");
           }
           else
           {
            LOG(DEBUG,"connect成功");
           }
           return;


        }
        void SetSocketAddrReuse() override
        {
            int opt = 1;
            ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        }
        int Recv(std::string *out) override
        {
           char buf[4096];
            int n=recv(_sockfd,buf,sizeof(buf)-1,0);
            if(n<0)
           {
            LOG(ERROR,"recv失败");
           }
           else
           {
            LOG(DEBUG,"recv成功");
           }
           if (n > 0)
            {
                buf[n] = 0;
                *out = buf ;// ??? +=
            }
           
           return;


        }
        int Send(const std::string &in) override
        {
            int n=send(_sockfd,in.c_str(),sizeof(in),0);
            return n;
        }
        int SockFd() override
        {
            return _sockfd;
        }
        void Close() override
        {
            if (_sockfd > -1)
                ::close(_sockfd);
        }

    private:
        int _sockfd;
    };
}